package com.palm.vue;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;


public class ScriptScope {

    private static final Set<String> controls = new HashSet<>(Arrays.asList("if", "for", "while", "with"));

    /**
     * 提取全局变量
     *
     * @param code
     * @return
     */
    public static Set<String> globalVars(String code) {
        Set vars = new HashSet();
        if (code == null || code.trim().length() == 0) {
            return vars;
        }

        //变换function 为 let方式
        code = code.replaceAll("function\\s+(\\w+)\\s*?\\(", "let $1=(");
        int blokIdx = 0;
        int l = code.length();
        for (int i = 0; i < l; i++) {
            char c = code.charAt(i);
            if (c == '/') {//判断是否是注释
                if (i < l - 2) {
                    if ("/*".equals(code.substring(i, i + 2))) {
                        //跳过注释
                        int a = code.indexOf("*/", i);
                        if (a > -1) {
                            i = a + 1;
                            continue;
                        }
                    }
                    if ("//".equals(code.substring(i, i + 2))) {//行注释
                        //跳过注释
                        int a = code.indexOf("\n", i);
                        if (a > -1) {
                            i = a;
                            continue;
                        }
                    }
                }
            }
            if (c == '"') {//跳过字符串
                int a = code.indexOf('"', i + 1);
                if (a > -1) {
                    i = a;
                    continue;
                }
            }
            if (c == '\'') {//跳过字符串
                int a = code.indexOf('\'', i + 1);
                if (a > -1) {
                    i = a;
                    continue;
                }
            }
            if (c == '`') {//跳过字符串
                int a = code.indexOf('`', i + 1);
                if (a > -1) {
                    i = a;
                    continue;
                }
            }
            //跳过控制语句，for(...) while(...) if(...) with(...)
            if (c == '(') {//
                String wd = beforeSimpleWord(code, i);
                if (controls.contains(wd)) {
                    int a = code.indexOf(')', i + 1);
                    if (a > -1) {
                        i = a;
                        continue;
                    }
                }
            }
            if (c == '{') {//跳过代码块
                if (blokIdx == 0) {//看看是否为代码快){
                    int next = findNextBlocIndex(code, i);
                    if (next > -1) {
                        char nextChar = findNextChar(code, next + 1);
                        if (nextChar == '=') {
                            String sub = code.substring(i, next + 1);
                            sub = sub.replaceAll("(\\w+:)|\\{|\\}|\\s+", "").trim();
                            if(sub.length()>0){
                                vars.addAll(Arrays.asList(sub.split(",")));
                            }
                            i = next + 1;
                            continue;
                        }
                    }

                }
                blokIdx++;
            } else if (c == '}') {
                blokIdx--;
            }

            if (blokIdx == 0) {
                if (c == '=') {
                    String words = beforeWord(code, i - 1);
                    words = words.replaceAll("(\\w+:)|\\s+|\\(\\)", "").trim();
                    if(words.length()>0){
                        vars.addAll(Arrays.asList(words.split(",")));
                    }

                }
            }
        }
        return vars;
    }

    /**
     * 找到下一个块闭合的位置
     *
     * @param code  全部源代码
     * @param start 起始位置
     * @return
     */
    private static int findNextBlocIndex(String code, int start) {
        int blokIdx = 0;
        int l = code.length();
        for (int i = start; i < l; i++) {
            char c = code.charAt(i);
            if (c == '/') {//判断是否是注释
                if (i < l - 2) {
                    if ("/*".equals(code.substring(i, i + 2))) {
                        //跳过注释
                        int a = code.indexOf("*/", i);
                        if (a > -1) {
                            i = a + 1;
                            continue;
                        }
                    }
                    if ("//".equals(code.substring(i, i + 2))) {//行注释
                        //跳过注释
                        int a = code.indexOf("\n", i);
                        if (a > -1) {
                            i = a;
                            continue;
                        }
                    }
                }
            }
            if (c == '"') {//跳过字符串
                int a = code.indexOf('"', i + 1);
                if (a > -1) {
                    i = a;
                    continue;
                }
            }
            if (c == '\'') {//跳过字符串
                int a = code.indexOf('\'', i + 1);
                if (a > -1) {
                    i = a;
                    continue;
                }
            }
            if (c == '`') {//跳过字符串
                int a = code.indexOf('`', i + 1);
                if (a > -1) {
                    i = a;
                    continue;
                }
            }
            if (c == '{') {//跳过代码块
                blokIdx++;
            } else if (c == '}') {
                blokIdx--;
            }
            if (blokIdx == 0) {
                return i;
            }
        }
        return -1;
    }

    //找到下一个非空白字符
    private static char findNextChar(String code, int last) {
        for (int i = last; i < code.length(); i++) {
            char c = code.charAt(i);
            if (c != ' ' && c != '\n') {
                return c;
            }
        }
        return 0;
    }

    private static final String tks = " ,][{}\n";

    //查找这个位置前的首个单词
    private static String beforeSimpleWord(String code, int idx) {
        StringBuffer sb = new StringBuffer();
        boolean started = false;
        for (int i = idx - 1; i >= 0; i--) {
            char c = code.charAt(i);
            if (tks.indexOf(c) > -1) {
                if (started) {
                    break;
                }
            } else {
                started = true;
                sb.append(c);
            }
        }
        return sb.reverse().toString();
    }

    //查找在这个位置前的词，包含{},[]
    private static String beforeWord(String code, int idx) {
        StringBuffer sb = new StringBuffer();
        boolean started = false;
        char end = 0;
        for (int i = idx; i >= 0; i--) {
            char c = code.charAt(i);
            if (c == ' ' || c == '\n') {
                if (started) {
                    break;
                }
            } else if (c == '}') {
                end = '{';
            } else if (c == ']') {
                end = '[';
            } else if (c == ',' && end == 0) {
                break;
            } else if (c == end) {
                break;
            } else {
                started = true;
                sb.append(c);
            }
        }
        return sb.reverse().toString();
    }
}
